﻿using Microsoft.Win32;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace System.Windows.Forms
{
	[Serializable, ToolboxItem(false), DesignTimeVisible(false), DefaultProperty("Header"), TypeConverter(typeof(ListViewGroupExConverter))]
	public class ListViewGroupEx : ISerializable
	{
		private ListViewEx listView;
		private bool? collapsed, hidden, noheader, focused, selected, collapsible, subseted, subsetlinkfocused;
		private string header, footer, task, subtitle, descTop, descBottom;
		private HorizontalAlignment headerAlignment, footerAlign = HorizontalAlignment.Left;
		private int id, titleImageIndex;
		private System.Windows.Forms.ListView.ListViewItemCollection items;

		private static int nextID;

		public ListViewGroupEx() : this(typeof(ListViewGroupEx).Name)
		{
		}

		public ListViewGroupEx(string header)
		{
			this.header = header;
			this.id = nextID++;
		}

		private ListViewGroupEx(SerializationInfo info, StreamingContext context)
		{
			this.Deserialize(info, context);
		}

		public ListViewGroupEx(string key, string headerText) : this(headerText)
		{
			this.Name = key;
		}

		public ListViewGroupEx(string header, HorizontalAlignment headerAlignment) : this(header)
		{
			this.headerAlignment = headerAlignment;
		}

		[DefaultValue(false), Category("Appearance")]
		public bool Collapsed
		{
			get { return GetState(NativeMethods.ListViewGroupState.Collapsed | NativeMethods.ListViewGroupState.Normal, ref this.collapsed); }
			set { SetState(NativeMethods.ListViewGroupState.Collapsed | NativeMethods.ListViewGroupState.Normal, value, ref this.collapsed); }
		}

		[DefaultValue(false), Category("Behavior")]
		public bool Collapsible
		{
			get { return GetState(NativeMethods.ListViewGroupState.Collapsible, ref this.collapsible); }
			set { SetState(NativeMethods.ListViewGroupState.Collapsible, value, ref this.collapsible); }
		}

		[DefaultValue(""), Category("Appearance")]
		public string DescriptionBottom
		{
			get { return descBottom != null ? descBottom : string.Empty; }
			set
			{
				if (descBottom != value)
				{
					this.descBottom = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[DefaultValue(""), Category("Appearance")]
		public string DescriptionTop
		{
			get { return descTop != null ? descTop : string.Empty; }
			set
			{
				if (descTop != value)
				{
					this.descTop = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[DefaultValue(false), Category("Appearance")]
		public bool Focused
		{
			get { return GetState(NativeMethods.ListViewGroupState.Focused, ref this.focused); }
			set { SetState(NativeMethods.ListViewGroupState.Focused, value, ref this.focused); }
		}

		[DefaultValue(""), Category("Appearance")]
		public string Footer
		{
			get { return footer != null ? footer : string.Empty; }
			set
			{
				if (footer != value)
				{
					this.footer = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[DefaultValue(0), Category("Appearance")]
		public HorizontalAlignment FooterAlignment
		{
			get { return footerAlign; }
			set
			{
				if (footerAlign != value)
				{
					this.footerAlign = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[DefaultValue(""), Category("Appearance")]
		public string Header
		{
			get { return (this.header == null) ? string.Empty : this.header; }
			set
			{
				if (this.header != value)
				{
					this.header = value;
					if (this.listView != null)
						this.listView.RecreateHandleInternal();
				}
			}
		}

		[DefaultValue(0), Category("Appearance")]
		public HorizontalAlignment HeaderAlignment
		{
			get { return this.headerAlignment; }
			set
			{
				EnumUtil.CheckHasValue<HorizontalAlignment>(value);
				if (this.headerAlignment != value)
				{
					this.headerAlignment = value;
					this.UpdateListView();
				}
			}
		}

		private void UpdateListView()
		{
			if ((this.listView != null) && this.listView.IsHandleCreated)
				this.listView.UpdateGroupNative(this);
		}

		[DefaultValue(false), Category("Appearance")]
		public bool Hidden
		{
			get { return GetState(NativeMethods.ListViewGroupState.Hidden, ref this.hidden); }
			set { SetState(NativeMethods.ListViewGroupState.Hidden, value, ref this.hidden); }
		}

		[Browsable(false)]
		public ListView.ListViewItemCollection Items
		{
			get
			{
				if (this.items == null)
					this.items = new ListView.ListViewItemCollection(new ListViewGroupItemCollection(this));
				return this.items;
			}
		}

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
		public ListViewEx ListView
		{
			get { return listView; }
			internal set { if (value != listView) listView = value; }
		}

		[DefaultValue(""), Category("Behavior"), Browsable(true)]
		public string Name { get; set; }

		[DefaultValue(false), Category("Appearance")]
		public bool NoHeader
		{
			get { return GetState(NativeMethods.ListViewGroupState.NoHeader, ref this.noheader); }
			set { SetState(NativeMethods.ListViewGroupState.NoHeader, value, ref this.noheader); }
		}

		[DefaultValue(false), Category("Appearance")]
		public bool Selected
		{
			get { return GetState(NativeMethods.ListViewGroupState.Selected, ref this.selected); }
			set { SetState(NativeMethods.ListViewGroupState.Selected, value, ref this.selected); }
		}

		[DefaultValue(false), Category("Appearance")]
		public bool Subseted
		{
			get { return GetState(NativeMethods.ListViewGroupState.Subseted, ref this.subseted); }
			set { SetState(NativeMethods.ListViewGroupState.Subseted, value, ref this.subseted); }
		}

		[DefaultValue(false), Category("Appearance")]
		public bool SubsetLinkFocused
		{
			get { return GetState(NativeMethods.ListViewGroupState.SubsetLinkFocused, ref this.subsetlinkfocused); }
			set { SetState(NativeMethods.ListViewGroupState.SubsetLinkFocused, value, ref this.subsetlinkfocused); }
		}

		[DefaultValue(""), Category("Appearance")]
		public string Subtitle
		{
			get { return subtitle != null ? subtitle : string.Empty; }
			set
			{
				if (subtitle != value)
				{
					this.subtitle = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[Localizable(false), Bindable(true), TypeConverter(typeof(StringConverter)), Category("Data"), DefaultValue((string)null)]
		public object Tag { get; set; }

		[DefaultValue(""), Category("Appearance")]
		public string Task
		{
			get { return task != null ? task : string.Empty; }
			set
			{
				if (task != value)
				{
					this.task = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		[RefreshProperties(RefreshProperties.Repaint), RelatedImageList("ListView.GroupHeaderImageList"), Localizable(true), DefaultValue(0), Description("Index of image to display with group"), Category("Behavior"), TypeConverter(typeof(ImageIndexConverter)), Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
		public int TitleImageIndex
		{
			get { return titleImageIndex; }
			set
			{
				if (titleImageIndex != value)
				{
					titleImageIndex = value;
					if (this.ListView != null)
						this.ListView.UpdateGroupNative(this);
				}
			}
		}

		internal int ID
		{
			get { return id; }
		}

		internal void GetSetState(out NativeMethods.ListViewGroupState m, out NativeMethods.ListViewGroupState s)
		{
			m = s = NativeMethods.ListViewGroupState.Normal;
			if (collapsed.HasValue) { m |= NativeMethods.ListViewGroupState.Collapsed; if (collapsed.Value) s |= NativeMethods.ListViewGroupState.Collapsed; }
			if (collapsible.HasValue) { m |= NativeMethods.ListViewGroupState.Collapsible; if (collapsible.Value) s |= NativeMethods.ListViewGroupState.Collapsible; }
			if (focused.HasValue) { m |= NativeMethods.ListViewGroupState.Focused; if (focused.Value) s |= NativeMethods.ListViewGroupState.Focused; }
			if (hidden.HasValue) { m |= NativeMethods.ListViewGroupState.Hidden; if (hidden.Value) s |= NativeMethods.ListViewGroupState.Hidden; }
			if (noheader.HasValue) { m |= NativeMethods.ListViewGroupState.NoHeader; if (noheader.Value) s |= NativeMethods.ListViewGroupState.NoHeader; }
			if (selected.HasValue) { m |= NativeMethods.ListViewGroupState.Selected; if (selected.Value) s |= NativeMethods.ListViewGroupState.Selected; }
			if (subseted.HasValue) { m |= NativeMethods.ListViewGroupState.Subseted; if (subseted.Value) s |= NativeMethods.ListViewGroupState.Subseted; }
			if (subsetlinkfocused.HasValue) { m |= NativeMethods.ListViewGroupState.SubsetLinkFocused; if (subsetlinkfocused.Value) s |= NativeMethods.ListViewGroupState.SubsetLinkFocused; }
		}

		private void Deserialize(SerializationInfo info, StreamingContext context)
		{
			int num = 0;
			SerializationInfoEnumerator enumerator = info.GetEnumerator();
			while (enumerator.MoveNext())
			{
				SerializationEntry current = enumerator.Current;
				switch (current.Name)
				{
					case "Header":
						this.Header = (string)current.Value;
						break;
					case "HeaderAlignment":
						this.HeaderAlignment = (HorizontalAlignment)current.Value;
						break;
					case "Tag":
						this.Tag = (string)current.Value;
						break;
					case "ItemsCount":
						num = (int)current.Value;
						break;
					case "Name":
						this.Name = (string)current.Value;
						break;
					case "DescriptionBottom":
						this.descBottom = (string)current.Value;
						break;
					case "DescriptionTop":
						this.descTop = (string)current.Value;
						break;
					case "Footer":
						this.footer = (string)current.Value;
						break;
					case "FooterAlignment":
						this.footerAlign = (HorizontalAlignment)current.Value;
						break;
					case "Subtitle":
						this.subtitle = (string)current.Value;
						break;
					case "Task":
						this.task = (string)current.Value;
						break;
					case "TitleImageIndex":
						titleImageIndex = (int)current.Value;
						break;
					case "GroupState":
						var state = (NativeMethods.ListViewGroupState)current.Value;
						if ((state & NativeMethods.ListViewGroupState.Collapsed) != 0) collapsed = true;
						if ((state & NativeMethods.ListViewGroupState.Collapsible) != 0) collapsible = true;
						if ((state & NativeMethods.ListViewGroupState.Focused) != 0) focused = true;
						if ((state & NativeMethods.ListViewGroupState.Hidden) != 0) hidden = true;
						if ((state & NativeMethods.ListViewGroupState.NoHeader) != 0) noheader = true;
						if ((state & NativeMethods.ListViewGroupState.Selected) != 0) selected = true;
						if ((state & NativeMethods.ListViewGroupState.Subseted) != 0) subseted = true;
						if ((state & NativeMethods.ListViewGroupState.SubsetLinkFocused) != 0) subsetlinkfocused = true;
						this.ListView.SetGroupState(this, state, true);
						break;
					default:
						break;
				}
			}
			if (num > 0)
			{
				ListViewItem[] items = new ListViewItem[num];
				for (int i = 0; i < num; i++)
					items[i] = (ListViewItem)info.GetValue("Item" + i, typeof(ListViewItem));
				this.Items.AddRange(items);
			}
		}

		[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Header", this.Header);
			info.AddValue("HeaderAlignment", this.HeaderAlignment);
			info.AddValue("Tag", this.Tag);
			if (!string.IsNullOrEmpty(this.Name))
				info.AddValue("Name", this.Name);
			if ((this.items != null) && (this.items.Count > 0))
			{
				info.AddValue("ItemsCount", this.Items.Count);
				for (int i = 0; i < this.Items.Count; i++)
					info.AddValue("Item" + i.ToString(CultureInfo.InvariantCulture), this.Items[i], typeof(ListViewItem));
			}
			if (descBottom != null)
				info.AddValue("DescriptionBottom", this.descBottom);
			if (descTop != null)
				info.AddValue("DescriptionTop", this.descTop);
			if (footer != null)
				info.AddValue("Footer", this.footer);
			if (footerAlign != 0)
				info.AddValue("FooterAlignment", this.footerAlign);
			if (subtitle != null)
				info.AddValue("Subtitle", this.subtitle);
			if (task != null)
				info.AddValue("Task", this.task);
			info.AddValue("TitleImageIndex", titleImageIndex);
			info.AddValue("GroupState", this.ListView.GetGroupState(this));
		}

		private bool GetState(NativeMethods.ListViewGroupState item, ref bool? localVar)
		{
			if (this.ListView != null)
			{
				NativeMethods.ListViewGroupState s = this.ListView.GetGroupState(this, item);
				localVar = ((s & item) != 0);
			}
			return localVar.GetValueOrDefault(false);
		}

		private void SetState(NativeMethods.ListViewGroupState item, bool on, ref bool? localVar)
		{
			if (this.ListView != null)
				this.ListView.SetGroupState(this, item, on);
			localVar = on;
		}
	}

	internal class ListViewGroupExConverter : TypeConverter
	{
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			return ((((sourceType == typeof(string)) && (context != null)) && (context.Instance is ListViewItem)) || base.CanConvertFrom(context, sourceType));
		}

		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			return ((destinationType == typeof(InstanceDescriptor)) || ((((destinationType == typeof(string)) && (context != null)) && (context.Instance is ListViewItem)) || base.CanConvertTo(context, destinationType)));
		}

		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			if (value is string)
			{
				string str = ((string)value).Trim();
				if ((context != null) && (context.Instance != null))
				{
					ListViewItem instance = context.Instance as ListViewItem;
					if ((instance != null) && (instance.ListView != null))
					{
						foreach (ListViewGroupEx group in ((ListViewEx)instance.ListView).Groups)
						{
							if (group.Header == str)
							{
								return group;
							}
						}
					}
				}
			}
			if ((value != null) && !value.Equals("None"))
			{
				return base.ConvertFrom(context, culture, value);
			}
			return null;
		}

		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
		{
			if (destinationType == null)
			{
				throw new ArgumentNullException("destinationType");
			}
			if ((destinationType == typeof(InstanceDescriptor)) && (value is ListViewGroupEx))
			{
				ListViewGroupEx group = (ListViewGroupEx)value;
				ConstructorInfo constructor = typeof(ListViewGroupEx).GetConstructor(System.Type.EmptyTypes);
				if (constructor != null)
				{
					return new InstanceDescriptor(constructor, null, false);
				}
			}
			if ((destinationType == typeof(string)) && (value == null))
			{
				return "None";
			}
			return base.ConvertTo(context, culture, value, destinationType);
		}

		public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
		{
			if ((context != null) && (context.Instance != null))
			{
				ListViewItem instance = context.Instance as ListViewItem;
				if ((instance != null) && (instance.ListView != null))
				{
					ArrayList values = new ArrayList();
					foreach (ListViewGroup group in instance.ListView.Groups)
					{
						values.Add(group);
					}
					values.Add(null);
					return new TypeConverter.StandardValuesCollection(values);
				}
			}
			return null;
		}

		public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
		{
			return true;
		}

		public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
		{
			return true;
		}
	}
}